{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 卷积层经典网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn, optim\n",
    "from torch.autograd import Variable\n",
    "from torch.nn import init"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## LeNet\n",
    "7层，其中2层卷积和2层池化层交替出现，最后输出3层全连接得到整体的效果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Lenet(nn.Module) :\n",
    "    def __init__(self) :\n",
    "        super().__init__()\n",
    "        \n",
    "        layer1 = nn.Sequential()\n",
    "        layer1.add_module('conv1', nn.Conv2d(1, 6, 3, padding=1))\n",
    "        layer1.add_module('pool1', nn.MaxPool2d(2, 2))\n",
    "        self.layer1 = layer1\n",
    "        \n",
    "        layer2 = nn.Sequential()\n",
    "        layer2.add_module('conv2', nn.Conv2d(6, 16, 5))\n",
    "        layer2.add_module('pool2', nn.MaxPool2d(2, 2))\n",
    "        self.layer2 = layer2\n",
    "        \n",
    "        layer3 = nn.Sequential()\n",
    "        layer3.add_module('fc1', nn.Linear(400, 120))\n",
    "        layer3.add_module('fc2', nn.Linear(120, 84))\n",
    "        layer3.add_module('fc3', nn.Linear(84, 10))\n",
    "        self.layer3 = layer3\n",
    "        \n",
    "    def forward(self, x) :\n",
    "        x = self.layer1(x)\n",
    "        x = self.layer2(x)\n",
    "        x.view(x.size(0), -1)\n",
    "        x = self.layer3(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## AlexNet\n",
    "相比于LeNet层数更深，同事第一册引入激活层ReLU，在全连接层引入了Dropout层防止过拟合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class AlexNet(nn.Module) :\n",
    "    def __init__(self, num_classes) :\n",
    "        super().__init__()\n",
    "        self.features = nn.Sequential(\n",
    "            nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),\n",
    "            nn.ReLU(inplace=True),\n",
    "            nn.MaxPool2d(kernel_size=3, stride=2),\n",
    "            nn.Conv2d(64, 192, kernel_size=5, padding=2),\n",
    "            nn.ReLU(inplace=True),\n",
    "            nn.MaxPlool2d(kernel_size=3, stride=2),\n",
    "            nn.Conv2d(192, 384, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Conv2d(384, 256, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Conv2d(256, 256, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.MaxPool2d(kernel_size=3, stride=2)\n",
    "        )\n",
    "        \n",
    "        self.classifier = nn.Sequential(\n",
    "            nn.Dropout(),\n",
    "            nn.Linear(256 * 6 * 6, 4096),\n",
    "            nn.ReLU(True),\n",
    "            nn.Dropout(),\n",
    "            nn.Linear(4096, 4096),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(4096, num_classes)\n",
    "        )\n",
    "        \n",
    "    def forward(self, x) :\n",
    "        x = self.features(x)\n",
    "        x = x.view(x.size(0), 256 * 256 * 256)\n",
    "        x = self.classifier(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## VGGNet\n",
    "相比于AlexNet, 它使用更多小的滤波器，层叠很多小的滤波器的感受野盒一个大的滤波器是相同的， 还能减小参数，同时有更深的网络结构"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class VGG(nn.Module) :\n",
    "    def __init__(self, num_classes) :\n",
    "        super().__init__()\n",
    "        \n",
    "        self.features = nn.Sequential(\n",
    "            nn.Conv2d(3, 64, kernel_size=3, pading=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Conv2d(64, 64, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.MaxPool2d(kernel_sze=2, stride=2),\n",
    "            nn.Conv2d(64, 128, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Conv2d(128, 128, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.MaxPool2d(kernel_size=2,stride=2),\n",
    "            nn.Conv2d(128, 256, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Conv2d(256, 256, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Conv2d(256, 256, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.MaxPool2d(kernel_size=2, stride=2),\n",
    "            nn.Conv2d(256, 512, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Conv2d(512, 512, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Conv2d(512, 512, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Conv2d(512, 512, kernel_size=3, padding=1),\n",
    "            nn.ReLU(True),\n",
    "            nn.MaxPool2d(kernel_size=2, stride=2)\n",
    "        )\n",
    "        \n",
    "        self.classifier = nn.Sequential(\n",
    "            nn.Linear(512 * 7 * 7, 4096),\n",
    "            nn.ReLU(True),\n",
    "            nn.Dropout(),\n",
    "            nn.Linear(4096, 4096),\n",
    "            nn.ReLU(True),\n",
    "            nn.Dropout(),\n",
    "            nn.Linear(4096, num_classes)\n",
    "        )\n",
    "        \n",
    "        self._initialize_weights()\n",
    "    def forward(self, x) :\n",
    "        x = self.features(x)\n",
    "        x = x.view(x.size(0), -1)\n",
    "        x = self.classifier(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "VGG只是对网络层进行不断叠加，并没有太多创新\n",
    "\n",
    "---\n",
    "## GoogleNet的Inception模块\n",
    "Inception模块设计了一个局部的网络拓扑结构，然后将这些模块堆叠在一起形成一个抽象网络结构。具体来说就是运用几个并行的滤波器对水乳进行卷积盒池化，这些滤波器有不同的感受野，做后将输出的结果按深度拼接在一起形成输出层。\n",
    "\n",
    "新的Inception模块增加了一些 1 × 1的卷积层来降低输入层的难度，使网络参数减少，从而减少了网络的复杂性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch.nn.functional as F\n",
    "\n",
    "class BasicConv2d(nn.Module) :\n",
    "    def __init__(self, in_channels, out_channels, **kwargs) :\n",
    "        super().__init__()\n",
    "        self.conv = nn.Conv2d(in_channels, out_channels, bias=False, **kwargs)\n",
    "        self.bn = nn.BatchNorm2d(out_channels, eps=0.001)\n",
    "    \n",
    "    def forward(self, x) :\n",
    "        x = self.conv(x)\n",
    "        x = self.bn(x)\n",
    "        return x\n",
    "\n",
    "class Inception(nn.Module) :\n",
    "    def __init__(self, in_channels, out_channels) :\n",
    "        super().__init__()\n",
    "        self.branch1x1 = BasicConv2d(in_channels, 64, kernel_size=1)\n",
    "        \n",
    "        self.branch5x5_1 = BasicConv2d(in_channels, 48, kernel_size=1)\n",
    "        self.branch5x5_2 = BasicConv2d(48, 64, kernel_size=5, padding=2)        \n",
    "        \n",
    "        self.branch3x3db1_1 = BasicConv2d(in_channels, 64, kernel_size=1)\n",
    "        slef.branch3x3db1_2 = BasicConv2d(64, 96, kernel_size=3, padding=1)\n",
    "        self.branch3x3db1_3 = BasicConv2d(96, 96, kernel_size=3, padding=1)\n",
    "        \n",
    "        self.branch_pool = BasicConv2d(in_channels, pool_features, kernel_size=1)\n",
    "    \n",
    "    def forward(self, x) :\n",
    "        branch1x1 = self.branch1x1(x)\n",
    "        \n",
    "        branch5x5 = self.branch5x5_1(x)\n",
    "        branch5x5 = self.branch5x5_2(branch5x5)\n",
    "        \n",
    "        branch3x3db1 = self.branch3x3db1_1(x)\n",
    "        branch3x3db1 = self.branch3x3db1_2(branch3x3db1)\n",
    "        branch3x3db1 = self.branch3x3db1_3(branch3x3db1)\n",
    "        \n",
    "        branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)\n",
    "        branch_pool = self.branch_pool(branch_pool)\n",
    "        \n",
    "        out = [branch1x1, branch5x5, branch3x3db1, branch_pool]\n",
    "        return torch.cat(out, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
